using System.Linq.Expressions;
using GEM.Domain.Entities;
using GEM.Domain.Entities.App;
using GEM.Domain.Repositories;
using GEM.Infrastructure.DB;
using Microsoft.EntityFrameworkCore;

namespace GEM.Infrastructure.Repositories;

/// <summary>
/// 仓储接口实现类
/// </summary>

public class EfRepository<T> : IRepository<T> where T : EntityBase
{
    private readonly AppDbContext _db;
    private readonly DbSet<T> _tb;
    //依赖注入
    public EfRepository(AppDbContext db)
    {
        _db = db;
        _tb = db.Set<T>();
    }

    // 将一个 未跟踪的实体对象 关联到当前数据库上下文，使其进入已跟踪状态
    public void Attach(T entity)
    {
        _db.Attach(entity);
    }

    /// <summary>
    /// 获取可查询的IQueryable对象
    /// </summary>
    /// <returns>IQueryable对象</returns>
    public IQueryable<T> GetQueryable()
    {
        return _tb.AsNoTracking();
    }

    public async Task<T> CreateAsync(T entity)
    {
        var obj = (await _tb.AddAsync(entity)).Entity;
        await _db.SaveChangesAsync();
        return obj;
    }

    //软删除
    public async Task DeleteAsync(T entity)
    {
        entity.IsDeleted = true;
        await UpdateAsync(entity);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="predicate"></param>
    /// <param name="includes"></param>
    /// <returns></returns>
    public async Task<T?> GetSingleWithIncludesAsync(
    Expression<Func<T, bool>> predicate,
    params Expression<Func<T, object>>[] includes)
    {
        IQueryable<T> query = _tb;
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        return await query.FirstOrDefaultAsync(predicate);
    }

    // 获取指定ID的实体对象，并包含指定的导航属性
    // 这里的includes参数可以传入多个导航属性进行包含查询
    public async Task<T?> GetByIdWithIncludesAsync(Guid id, params Expression<Func<T, object>>[] includes)
    {
        IQueryable<T> query = _tb;
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        return await query.FirstOrDefaultAsync(e => e.Id == id);
    }

    public async Task<int> DeleteAsync(Guid id)
    {
        var obj = await GetByIdAsync(id);
        if (obj == null)
        {
            return 0;
        }
        _tb.Remove(obj);
        await _db.SaveChangesAsync();
        return 1;
    }

    public async Task<IEnumerable<T>> GetAllAsync()
    {
        return await _tb.AsNoTracking().ToListAsync();
    }

    public async Task<T?> GetByIdAsync(Guid id)
    {
        return await _tb.FindAsync(id);
    }

    public async Task UpdateAsync(T entity)
    {
        _tb.Update(entity);
        await _db.SaveChangesAsync();
    }

    public async Task<(IEnumerable<T> Items, int TotalCount)> GetPagedAsync(int pageIndex, int pageSize, params Expression<Func<T, object>>[] includes)
    {
        IQueryable<T> query = _tb.AsNoTracking();
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        var total = await query.CountAsync();
        var items = await query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
        return (items, total);
    }

    // 实现IRepository中特定于其他实体的方法（返回null或抛出异常）
    public Task<AppUser?> GetUserWithRolesAsync(Guid userId)
    {
        throw new NotImplementedException("此方法不适用于通用实体");
    }

    public Task<AppRole?> GetRoleWithUsersAsync(Guid roleId)
    {
        throw new NotImplementedException("此方法不适用于通用实体");
    }

    public Task<AppPermission?> GetPermissionWithRolesAsync(Guid roleId)
    {
        throw new NotImplementedException("此方法不适用于通用实体");
    }

    public Task<AppRole?> GetRoleWithPermissionsAsync(Guid roleId)
    {
        throw new NotImplementedException("此方法不适用于通用实体");
    }
}